package com.antgroup.seckill.business.goods.service.impl;

import com.alibaba.fastjson.JSON;
import com.antgroup.seckill.business.common.enums.SequenceNameEnum;
import com.antgroup.seckill.business.common.exception.GlobalException;
import com.antgroup.seckill.business.common.kafka.KafkaSender;
import com.antgroup.seckill.business.common.rocketmq.RocketMqSender;
import com.antgroup.seckill.business.common.vo.request.GoodsQueryRequest;
import com.antgroup.seckill.business.common.vo.request.GoodsRequest;
import com.antgroup.seckill.business.common.vo.request.UpdateGoodsRequest;
import com.antgroup.seckill.business.common.vo.response.GoodsVo;
import com.antgroup.seckill.business.common.vo.response.RespBean;
import com.antgroup.seckill.business.goods.mapper.GoodsMapper;
import com.antgroup.seckill.business.goods.model.Goods;
import com.antgroup.seckill.business.goods.model.SeckillMessage;
import com.antgroup.seckill.business.goods.model.User;
import com.antgroup.seckill.business.goods.service.IGoodsService;
import com.antgroup.seckill.business.utils.DateUtil;
import com.antgroup.seckill.business.utils.SequenceUtil;
import com.antgroup.seckill.business.utils.UUIDUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.global.Global;
import org.elasticsearch.search.aggregations.bucket.global.GlobalAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.MaxAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.*;

import static com.antgroup.seckill.business.common.enums.RespBeanEnum.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author wangxy
 * @since 2024-07-30
 */
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements IGoodsService {

    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private RocketMqSender rocketMqSender;

    @Autowired
    private RestHighLevelClient esClient;

    @Autowired
    private KafkaSender kafkaSender;

    @Override
    public List<GoodsVo> queryAllGoods() {
        List<GoodsVo> goodsVos = goodsMapper.queryAllGoods();
        return goodsVos;
    }

    @Override
    public GoodsVo queryGoodsByGoodsId(String goodsId) {
        return goodsMapper.queryGoodsByGoodsId(goodsId);
    }

    @Override
    public void saveGoods(GoodsRequest request, User user) {
        Goods goods = new Goods();
        goods.setId(SequenceUtil.getSequenceId(SequenceNameEnum.OS_ORDER.getCode()));
        goods.setGoodsName(request.getGoodsName());
        goods.setGoodsPrice(request.getGoodsPrice());
        goods.setGoodsStock(request.getGoodsStock());
        goods.setGoodsDetail(request.getGoodsDetail());
        goods.setGoodsImg(request.getGoodsImg());
        goods.setGoodsTitle(request.getGoodsTitle());
        goods.setModifyTime(new Date());
        goods.setGmtTime(new Date());
        goodsMapper.insert(goods);

        //发送消息到rocketmq
        SeckillMessage seckillMessage = new SeckillMessage();
        seckillMessage.setGoogsId(goods.getId());
        seckillMessage.setUser(user);

        //异步发消息到rocketMq
        //rocketMqSender.sendMessage("goods:CREATE", JSON.toJSONString(seckillMessage));

        //异步发消息发往kafa
        kafkaSender.sendMessage("goods-save",JSON.toJSONString(seckillMessage));
    }

    /**
     * 更新商品
     *
     * @param request
     */
    @Override
    public void updateGoods(UpdateGoodsRequest request) {
        GoodsVo goodsVo = goodsMapper.queryGoodsByGoodsId(request.getId());
        if (Objects.isNull(goodsVo)) {
            throw new GlobalException(GOODS_NOT_EXIST);
        }
        Goods goods = new Goods();
        goods.setId(goodsVo.getId());
        goods.setGoodsName(request.getGoodsName());
        goods.setGoodsPrice(request.getGoodsPrice());
        goods.setGoodsStock(request.getGoodsStock());
        goods.setGoodsDetail(request.getGoodsDetail());
        goods.setGoodsImg(request.getGoodsImg());
        goods.setGoodsTitle(request.getGoodsTitle());
        goodsMapper.updateGoods(goods);

        //发送消息到rocketmq
        SeckillMessage seckillMessage = new SeckillMessage();
        seckillMessage.setGoogsId(goods.getId());

        //异步发消息到rocketMq
        rocketMqSender.sendMessage("goods:UPDATE", JSON.toJSONString(seckillMessage));

    }

    /**
     * 删除商品
     *
     * @param goodsId
     */
    @Override
    public void deleteGoodsById(String goodsId) {
        goodsMapper.deleteById(goodsId);

        //发送消息到rocketmq
        SeckillMessage seckillMessage = new SeckillMessage();
        seckillMessage.setGoogsId(goodsId);

        //异步发消息到rocketMq
        rocketMqSender.sendMessage("goods:DELETE", JSON.toJSONString(seckillMessage));
    }

    /**
     * es查询商品
     *
     * @param request
     * @return
     */
    @Override
    public List<GoodsVo> queryGoods(GoodsQueryRequest request) {
        List<GoodsVo> goodsList = new ArrayList<>();
        try {
            SearchRequest searchRequest = new SearchRequest("os_goods");
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

            // 添加查询条件
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            if (StringUtils.isNotBlank(request.getId())) {
                boolQueryBuilder.must(QueryBuilders.termQuery("id", request.getId()));
            }

            if (StringUtils.isNotBlank(request.getGoodsName())) {
                boolQueryBuilder.must(QueryBuilders.fuzzyQuery("goodsName", request.getGoodsName()).fuzziness(Fuzziness.AUTO));
            }

            if (StringUtils.isNotBlank(request.getGoodsDetail())) {
                boolQueryBuilder.should(QueryBuilders.matchQuery("goodsDetail", request.getGoodsDetail()));
            }

            if (Objects.nonNull(request.getStartPrice()) && Objects.nonNull(request.getEndPrice())) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("goodsPrice").gte(request.getStartPrice()).lt(request.getEndPrice());
                boolQueryBuilder.must(rangeQueryBuilder);
            }
            if (Objects.nonNull(request.getStartTime()) && Objects.nonNull(request.getEndTime())) {
                // 添加时间范围查询
                RangeQueryBuilder timeRangeQueryBuilder = QueryBuilders.rangeQuery("gmtTime")
                        .gte(DateUtil.getTimeStamp(request.getStartTime()))
                        .lt(DateUtil.getTimeStamp(request.getEndTime()));
                boolQueryBuilder.must(timeRangeQueryBuilder);
            }


            // 设置分页条件
            int page = request.getPageNumber();
            int size = request.getPageSize();
            int from = (page - 1) * size;

            searchSourceBuilder.from(from);
            searchSourceBuilder.size(size);
            searchSourceBuilder.sort("gmtTime", SortOrder.DESC);
            searchSourceBuilder.query(boolQueryBuilder);

            searchRequest.source(searchSourceBuilder);


            SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);

            // 解析查询结果
            SearchHits hits = searchResponse.getHits();
            for (SearchHit hit : hits) {
                // 将 JSON 格式的 _source 字段转换为 GoodsVo 对象
                GoodsVo goods = JSON.parseObject(hit.getSourceAsString(), GoodsVo.class);
                goodsList.add(goods);
            }
        } catch (IOException e) {
            throw new GlobalException(ES_ERROR);
        }
        return goodsList;
    }
}
